package Client;
/**
 *
 * I love this version of eclipse. I could babies with this version of eclipse
 * 
 */
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
//import java.awt.event.KeyEvent;
//import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.List;
//import java.text.DecimalFormat;

import javax.imageio.ImageIO;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JPanel;

import GameState.GameState;
import GameState.GameStateRender;
import GameState.Map.Wind;
import GameState.Projectiles.CannonBall;
import GameState.Ships.PirateShip;
import Server.Request;


/**
 * 
 * 
 * @author Tom
 *
 */

public class GamePanel extends JPanel implements Runnable {


	/* **********************************************************************************************************************************************************
	 * 																Things concerning the rendering the images													* 
	 ********************************************************************************************************************************************************** */
	private Image dbImage;

	//	private  final BufferedImage mWindImage;
	//	private final static String WIND_IMAGE_PATH = "windImage.png";



	/**
	 * String showing who has created this game
	 */
	private final static String GAME_VERSION = "Game Version 4.00, created By Steve, Tom & Davy";

	//private final int mScreenWidth;
	//private final int mScreenHeight;
	//private final static int DRAW_BALL_SIZE = 5;

	/* ***************************************************************************************************************************************************
	 * 																		Playing sound																 *
	 *************************************************************************************************************************************************** */
	private GameSoundManager mySoundz;

	/**
	 * The Outer Shell of the game that handles all the net working and the start up the closing of the
	 * inter program
	 */

	/* ***************************************************************************************************************************************************
	 * 																		Misc																		 *
	 *************************************************************************************************************************************************** */
	private GameClient mClienthell;
	private GameState mTheGame;
	private GameStateRender mTheGameRenderer;
	private static final long serialVersionUID = 1L;
	private volatile boolean running = true;



	/* ***************************************************************************************************************************************************
	 * 																Rendering on screen timing															 *
	 *************************************************************************************************************************************************** */

	/**
	 * interval for about a second.
	 */
	//	private final static long MAX_STATS_INTERVAL = 1000L;
	private final static int NO_DELAYS_PER_YEILD = 5;
	//private final static long MAX_STATS_INTERVAL = 1000L;
	/**
	 *  NUmber of frames per second
	 */
	//	private static int NUM_FPS = 10; 
	/**
	 * Variable which gives back statics about how the aimation loop is running. 
	 */
	//	private long statsInverval = 0L;
	//	private long prevStatsTime;
	//	private long totalElapsedTime = 0L;
	//	private long frameCount = 0;
	//
	//	private double fpsStore[];
	//	private long statsCount = 0; 
	//	private double averageFPS = 0.0;
	//
	//	private DecimalFormat df =  new DecimalFormat("0.##") ;  // decimal Format 2 d.p.
	//	private DecimalFormat timedf =  new DecimalFormat("0.####") ;  // decimal Format 4 d.p.
	private int period;
	/*
	 * test variables
	 */
	public boolean drawCir = true;


	/**
	 * All the variable to do with the calculating the 
	 */
	private long overSleepTime;
	private int noDelays = 0;
	private long excess = 0L;



	/* ***************************************************************************************************************************************************
	 * 																		Contructor																	 *
	 *************************************************************************************************************************************************** */


	/**
	 * 
	 * Constructor for the GamePanel. Adds in the outer shell of the program. 
	 * 
	 * @param mOuterShell the outer shell of the program.
	 * @throws IOException 
	 */
	public GamePanel( final GameClient clienthell, final int screenWidth, final int screenHeight) throws IOException
	{

		//Loading up all the images

		//		mWindImage = ImageIO.read( new File(WIND_IMAGE_PATH));
		//		mSeaImage = ImageIO.read( new File (SEA_IMAGE_PATH));
		//		
		//		mAnchorImage = ImageIO.read( new File(ANCHOR_IMAGE_PATH));
		//		mScreenWidth = screenWidth;
		//		mScreenHeight = screenHeight;

		mTheGameRenderer = new GameStateRender(this.WIDTH, this.HEIGHT);
		try {
			mySoundz = new GameSoundManager();
			mySoundz.playSounds(SoundTypez.BACKGROUND_MUSIC);
		} catch (UnsupportedAudioFileException e) {
			e.printStackTrace();
		} catch (Exception e) {

			e.printStackTrace();
		}

		//adds a new abstract key listener
		this.addKeyListener( new KeyListener(){

			public void keyPressed(final KeyEvent keyPress) {
				//System.out.println(keyPress.getKeyChar() +  " Down");
				try {
					interperateKeyPressDown(keyPress);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}

			public void keyReleased(final KeyEvent keyPress) {

				try {
					interperateKeyPressUp(keyPress);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}

			public void keyTyped(final KeyEvent keyPress) {}

			private void interperateKeyPressDown(final KeyEvent keyPress) throws RemoteException{


				System.out.println("Key down");


				switch (keyPress.getKeyCode()){

				case KeyEvent.VK_ESCAPE: // closes down the program

					mClienthell.closeClient();
					break;

				case  KeyEvent.VK_DOWN:
					break;

				case KeyEvent.VK_UP:

					mClienthell.requestForward();
					break;

				case KeyEvent.VK_LEFT:

					mClienthell.requestLeft();
					break;

				case KeyEvent.VK_RIGHT:
					mClienthell.requestRight();
					break;

				case KeyEvent.VK_Q:
					mClienthell.requestShootLeft();
					break;

				case KeyEvent.VK_W:
					mClienthell.requestShootRight();
					break;

				case KeyEvent.VK_A:
					mClienthell.requestAnchor();				
					break;
				}



			}

			private void interperateKeyPressUp(final KeyEvent keyPress) throws RemoteException{


			}


		});

		this.setBackground(Color.cyan);
		this.setOpaque(true);
		this.setVisible(true);
		this.mClienthell = clienthell;
		this.setEnabled(true);
		this.setFocusable(true);



	}

	public void run(){

		//		long beforeTime = 0L;
		//	long afterTime;
		//long timeDiff;


		while(running){

			// If there has been a remote exception being the server has shut down.
			//Then don't render the screen
//			try {
				renderGame();
//			} catch (RemoteException e) {
//				e.printStackTrace();
//				renderCrash();
//
//			}

			paintScreen();
			playSoundz();
			//beforeTime = napABit(beforeTime);

			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

		exitGame();

	}

	public void playSoundz(){

		/*try {

			for(int count  = 0 ; count  < myShips.size(); count++){

				Request []  shipRequests  = myShips.get(count).getRequests();				

				if (shipRequests[3] != null || shipRequests[4] != null){

					mySoundz.playSounds(SoundTypez.SHIP_SPLASH);
				}
			}

		} catch(Exception ex){

			System.err.println("Counld Not paly sound");
			ex.printStackTrace();

		}*/




	}

	/**
	 * 
	 * Decides how long to let this thread sleep for so that other threads can execute.
	 * 
	 * @param beforeTime the clock of the beginning of the update, render, paint, etc
	 * @return returns the new before time. 
	 */
	@SuppressWarnings("unused")
	private long napABit( final long beforeTime){

		final long afterTime = System.nanoTime();
		final long timeDiff = afterTime - beforeTime; 
		final long sleepTime = (period - timeDiff) - overSleepTime;  

		if (sleepTime > 0 ){

			try{
				Thread.sleep(sleepTime / 1000000L );
			}catch(InterruptedException e){
				overSleepTime  = ( System.nanoTime() - afterTime) - sleepTime;
			}

		} else { // frame took longer than the correct period

			excess -= sleepTime ; 
			overSleepTime = 0;

			if(++noDelays >=  NO_DELAYS_PER_YEILD){
				Thread.yield();
				noDelays = 0;
			}

		}



		return afterTime;


	}

	private void renderCrash(){



	}

	/**
	 * Renders the buffered image to the screen
	 */
	private void paintScreen(){

		Graphics g;

		try{



			g = this.getGraphics();
			if(g != null && dbImage != null){

				g.drawImage(dbImage, 0,0,  null);
				Toolkit.getDefaultToolkit().sync();
				g.dispose();
				dbImage = null;

			}


		}catch(Exception e ){

			System.err.println("Graphics conetex error" + e.toString());

		}


	}

	//
	// Rendering the Game
	//
	private void renderGame(){


		//		if(myShips == null || myBalls == null)
		//			System.err.println("Render Game Null pointer");
		//		else
		//		{
		//
		//
		//
		//
		this.dbImage = new BufferedImage(1000 * 3, 1000* 3, BufferedImage.TYPE_INT_RGB);   //new BufferedImage(mScreenWidth, mScreenHeight, BufferedImage.TYPE_INT_RGB);
		Graphics  dbGraphics = dbImage.getGraphics();
		//
		//
		//			BufferedImage centerBlock =  renderBlock();
		//
		//
		//			dbGraphics.drawImage(centerBlock, 0, 0, null);

		//Draws the sea on the screen
		//dbGraphics.drawImage(mSeaImage, 0,0,null);
		dbGraphics.drawImage( mTheGameRenderer.render(mTheGame, mClienthell.getPlayer()), 0, 0, null);



		/*
		 ************************************************************************************************
		 * 									Renders The hud 											*
		 ************************************************************************************************
		 */


		dbGraphics.setColor(Color.RED);

		//			BufferedImage windImage = 	renderWind(myWind.get(0));		
		//			dbGraphics.drawImage(windImage,	0, this.getHeight() - windImage.getHeight(), null);


		dbGraphics.drawChars(GAME_VERSION.toCharArray(), 0, GAME_VERSION.length(), 0, 10);
		//Renders the amount of ammo the player has to the screen
		//			char [] leftAmount = ("Left Ammo: " + Integer.toString(playerShip.getLeftAmoo())).toCharArray();
		//			char []  rightAmount = ("Right Ammo: " + Integer.toString(playerShip.getRightAmoo())).toCharArray();
		//			dbGraphics.drawChars(leftAmount, 0, leftAmount.length, 0, 20);  
		//			dbGraphics.drawChars(rightAmount, 0,rightAmount.length, 0, 40);
		//
		//			//Renders the amount of heath the player has to the screen
		//			char [] health = ( "Health: " + Integer.toString(playerShip.getHealth())	).toCharArray();
		//			dbGraphics.drawChars(health, 0, health.length, 0, 60);
		//
		//			//Draws the player name on the screen.
		//			char [] name = ("Name: " + playerShip.getName()).toCharArray();
		//			dbGraphics.drawChars(name, 0, name.length, 0, 70);
		//
		//			char [] score = ("Score: " + Integer.toString(playerShip.getScore()) ).toCharArray(); 
		//			dbGraphics.drawChars(score, 0, score.length, 0, 80);
		//
		//			char [] direction = ("Direction " + playerShip.getDirection()).toCharArray();
		//			dbGraphics.drawChars(direction, 0, direction.length, 0, 90);
		//
		//			char [] xvel = ("xvel " + playerShip.getXvel()).toCharArray();
		//			char [] yvel = ("yvel " + playerShip.getYvel()).toCharArray();
		//
		//			dbGraphics.drawChars(xvel, 0, xvel.length, 0, 100);
		//			dbGraphics.drawChars(yvel, 0, yvel.length, 0, 110);
		//
		//			char [] xvelChange = ("x vel change " + playerShip.getCalXvelChange()).toCharArray();
		//			char [] yvelChange = ("y vel change " + playerShip.getCalYvelChange()).toCharArray();
		//
		//			dbGraphics.drawChars(xvelChange, 0, xvelChange.length, 0, 120);
		//			dbGraphics.drawChars(yvelChange, 0, yvelChange.length, 0, 130);
		//
		//			char [] xpos = ("x pos " + playerShip.getX()).toCharArray();
		//			char [] ypos = ("y pos " + playerShip.getY()).toCharArray();
		//
		//
		//			dbGraphics.drawChars(xpos, 0, xpos.length, 0, 140);
		//			dbGraphics.drawChars(ypos, 0, ypos.length, 0, 150);

		//			if(drawCir){
		//				
		//				dbGraphics.drawArc(100, 100, 100, 100, 50, 100);
		//				
		//			}
		//			
		//
		//
		//		}
	}



	private void exitGame(){

		mClienthell.closeClient();
	}










}
